package db

import (
	"database/sql"
	"fmt"
	"log"
	"regexp"
	"strings"
	"time"

	"datasync/config"

	_ "github.com/go-sql-driver/mysql"
)

// CreateConnection 创建数据库连接
func CreateConnection(cfg *config.DatabaseConfig) (*sql.DB, error) {
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
		cfg.User, cfg.Password, cfg.Host, cfg.Port, cfg.DBName)

	// 打开数据库连接
	db, err := sql.Open("mysql", dsn)
	if err != nil {
		return nil, fmt.Errorf("打开数据库连接失败: %v", err)
	}

	// 设置连接池参数
	db.SetMaxOpenConns(20)
	db.SetMaxIdleConns(5)
	db.SetConnMaxLifetime(time.Minute * 5)

	// 测试连接
	if err := db.Ping(); err != nil {
		return nil, fmt.Errorf("测试数据库连接失败: %v", err)
	}

	log.Printf("成功连接到数据库: %s:%d/%s", cfg.Host, cfg.Port, cfg.DBName)
	return db, nil
}

// CloseConnection 关闭数据库连接
func CloseConnection(db *sql.DB) error {
	if db != nil {
		return db.Close()
	}
	return nil
}

// TableExists 检查表是否存在
func TableExists(db *sql.DB, tableName string) (bool, error) {
	query := `
		SELECT COUNT(*) 
		FROM INFORMATION_SCHEMA.TABLES 
		WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ?
	`

	var count int
	err := db.QueryRow(query, tableName).Scan(&count)
	if err != nil {
		return false, fmt.Errorf("检查表是否存在失败: %v", err)
	}

	return count > 0, nil
}

// ColumnInfo 列信息结构
type ColumnInfo struct {
	ColumnName string
	DataType   string
}

// GetTableSchema 获取表结构信息，返回字段名到数据类型的映射
func GetTableSchema(db *sql.DB, tableName string) (map[string]string, error) {
	query := `
		SELECT COLUMN_NAME, DATA_TYPE 
		FROM INFORMATION_SCHEMA.COLUMNS 
		WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ?
	`

	rows, err := db.Query(query, tableName)
	if err != nil {
		return nil, fmt.Errorf("查询表结构失败: %v", err)
	}
	defer rows.Close()

	schema := make(map[string]string)
	for rows.Next() {
		var columnName, dataType string
		if err := rows.Scan(&columnName, &dataType); err != nil {
			return nil, fmt.Errorf("扫描表结构失败: %v", err)
		}
		schema[columnName] = dataType
	}

	if err := rows.Err(); err != nil {
		return nil, fmt.Errorf("行迭代错误: %v", err)
	}

	return schema, nil
}

// GetTableCreateSQL 获取表创建SQL语句
func GetTableCreateSQL(db *sql.DB, tableName string) (string, error) {
	query := `
		SHOW CREATE TABLE 
	` + tableName

	var name, createSQL string
	err := db.QueryRow(query).Scan(&name, &createSQL)
	if err != nil {
		return "", fmt.Errorf("获取表创建SQL失败: %v", err)
	}

	return createSQL, nil
}

// CompareSchemas 比较源表和目标表结构差异，返回需要执行的ALTER语句
func CompareSchemas(sourceSchema, targetSchema map[string]string) []string {
	var alterStatements []string

	// 1. 检查源表有但目标表没有的字段，需要添加
	for col, dataType := range sourceSchema {
		if _, exists := targetSchema[col]; !exists {
			alterStatements = append(alterStatements, fmt.Sprintf("ALTER TABLE %%s ADD COLUMN %s %s;", col, dataType))
		}
	}

	// 2. 检查字段数据类型是否匹配，不匹配则修改
	for col, sourceType := range sourceSchema {
		if targetType, exists := targetSchema[col]; exists && sourceType != targetType {
			alterStatements = append(alterStatements, fmt.Sprintf("ALTER TABLE %%s MODIFY COLUMN %s %s;", col, sourceType))
		}
	}

	// 3. 检查目标表有但源表没有的字段，需要删除
	for col := range targetSchema {
		if _, exists := sourceSchema[col]; !exists {
			alterStatements = append(alterStatements, fmt.Sprintf("ALTER TABLE %%s DROP COLUMN %s;", col))
		}
	}

	// 4. 检查索引差异，源表有但目标表没有的索引，需要添加
	// 这里简单示例，实际根据具体需求设计

	// 5. 检查外键差异，源表有但目标表没有的外键，需要添加
	// 这里简单示例，实际根据具体需求设计

	return alterStatements
}

// SyncTableSchema 根据源表结构同步目标表结构
func SyncTableSchema(sourceDB, targetDB *sql.DB, sourceTable, targetTable string) error {
	// 获取源表和目标表结构
	sourceSchema, err := GetTableSchema(sourceDB, sourceTable)
	if err != nil {
		return fmt.Errorf("获取源表结构失败: %s, %v", sourceTable, err)
	}

	targetSchema, err := GetTableSchema(targetDB, targetTable)
	if err != nil {
		return fmt.Errorf("获取目标表结构失败: %s, %v", targetTable, err)
	}

	// 比较结构差异
	alterStatements := CompareSchemas(sourceSchema, targetSchema)
	if len(alterStatements) == 0 {
		log.Printf("源表 %s 和目标表 %s 结构一致，无需同步", sourceTable, targetTable)
		return nil
	}

	// 执行ALTER语句
	log.Printf("开始同步表结构 %s -> %s，需要执行 %d 项变更", sourceTable, targetTable, len(alterStatements))
	for _, stmt := range alterStatements {
		fullStmt := fmt.Sprintf(stmt, targetTable)
		log.Printf("执行结构变更: %s", fullStmt)

		_, err := targetDB.Exec(fullStmt)
		if err != nil {
			return fmt.Errorf("执行SQL失败: %v, SQL: %s", err, fullStmt)
		}
	}

	log.Printf("表结构同步完成: %s -> %s", sourceTable, targetTable)
	return nil
}

// CreateTableFromSource 根据源表结构创建目标表
func CreateTableFromSource(sourceDB, targetDB *sql.DB, sourceTable, targetTable string) error {
	// 获取源表创建SQL
	createSQL, err := GetTableCreateSQL(sourceDB, sourceTable)
	if err != nil {
		return fmt.Errorf("获取源表创建SQL失败: %v", err)
	}

	// 替换表名
	createSQL = strings.Replace(createSQL, "CREATE TABLE `"+sourceTable+"`", "CREATE TABLE `"+targetTable+"`", 1)
	// 移除AUTO_INCREMENT属性，避免同步时主键冲突
	createSQL = regexp.MustCompile(`AUTO_INCREMENT=\d+`).ReplaceAllString(createSQL, "")

	// 执行创建表语句
	log.Printf("执行创建表SQL: %s", createSQL)
	_, err = targetDB.Exec(createSQL)
	if err != nil {
		return fmt.Errorf("创建目标表失败: %v, SQL: %s", err, createSQL)
	}

	log.Printf("成功创建目标表: %s", targetTable)
	return nil
}
